
namespace NUtils
{
    public partial class Math
    {
        public class Vector
        {
            public double X;
            public double Y;
            public double Z;

            #region Constructors
            public Vector()
            {
                X = 0;
                Y = 0;
                Z = 0;
            }

            public Vector(double x, double y, double z)
            {
                X = x;
                Y = y;
                Z = z;
            }

            public Vector(Vector other)
            {
                X = other.X;
                Y = other.Y;
                Z = other.Z;
            }
            #endregion

            #region Methods
            public Vector Diff(Vector other)
            {
                return new Vector(X-other.X, Y-other.Y, Z-other.Z);
            }

            public Vector Add(Vector other)
            {
                return new Vector(X + other.X, Y + other.Y, Z + other.Z);
            }

            public double Dot(Vector other)
            {
                return X * other.X + Y * other.Y + Z * other.Z;
            }

            public Vector ScaleTo(double f)
            {
                Vector v = Unit;
                v.X *= f;
                v.Y *= f;
                v.Z *= f;
                return v;
            }

            public Vector ScaleBy(double f)
            {
                return new Vector(X*f, Y*f, Z*f);
            }

            public Vector Divide(double f)
            {
                return new Vector(X / f, Y / f, Z / f);
            }

            public bool NearlyEquals(Vector other, double epsilon)
            {
                return Diff(other).MagnitudeSquared < epsilon;
            }
            #endregion

            #region Properties
            public Vector Unit
            {
                get
                {
                    double mag = Magnitude;
                    return new Vector(X/mag, Y/mag, Z/mag);
                }
            }

            public double Magnitude
            {
                get
                {
                    return System.Math.Sqrt(Dot(this));
                }
            }

            public double MagnitudeSquared
            {
                get
                {
                    return Dot(this);
                }
            }
            #endregion

            #region Operators
            public static Vector operator -(Vector lhs, Vector rhs)
            {
                return lhs.Diff(rhs);
            }

            public static Vector operator +(Vector lhs, Vector rhs)
            {
                return lhs.Add(rhs);
            }

            public static Vector operator *(Vector lhs, double f)
            {
                return lhs.ScaleBy(f);
            }

            public static Vector operator /(Vector lhs, double f)
            {
                return lhs.Divide(f);
            }
            #endregion
        }
    }
}